<template>
  <div
    ref="DraggableSider"
    class="draggable-sider"
    :class="{ toggled, right: side === 'right' }"
    :style="{
      minWidth: calcMinWidth + 'px',
      maxWidth: maxWidth + 'px',
      width: width + 'px'
    }"
  >
    <div class="draggable-sider__content" v-show="!toggled">
      <slot name="content"></slot>
    </div>
    <div
      id="dragHandler"
      v-show="!toggled"
      class="border-handler"
      :style="{
        right: side === 'left' ? '-3px' : 'auto',
        left: side === 'right' ? '-3px' : 'auto'
      }"
      @mousedown.stop.prevent="onMouseDown"
    ></div>
    <sider-toggle
      slot="toggle"
      class="tree-toggle"
      :side="side"
      @click="onToggle"
    />
  </div>
</template>

<script>
import SiderToggle from './SiderToggle.vue'
let currentX = 0
let currentWidth = 0
export default {
  name: 'DraggableSider',
  components: {
    SiderToggle
  },
  props: {
    minWidth: {
      type: String | Number,
      default: 250
    },
    side: {
      type: String,
      default: 'left' // left right
    }
  },
  data () {
    return {
      toggled: false,
      dragging: false,
      calcMinWidth: 0,
      maxWidth: 'none',
      originWidth: 0, // 用于记录toggle前的width
      width: 0
    }
  },

  created () {
    this.calcMinWidth =
      this.originWidth =
      this.width =
        typeof this.minWidth === 'string'
          ? parseInt(this.minWidth)
          : this.minWidth
  },

  mounted () {
    document.documentElement.addEventListener(
      'mousemove',
      this.onMouseMove,
      true
    )
    document.documentElement.addEventListener('mouseup', this.onMouseUp, true)

    const parentNode = this.$refs.DraggableSider.parentNode
    this.maxWidth = Math.max(
      parentNode.offsetWidth / 2 || document.documentElement.clientWidth / 2,
      parseInt(this.minWidth)
    )
  },
  beforeDestroy () {
    document.documentElement.removeEventListener('mousemove', this.onMouseMove)
    document.documentElement.removeEventListener('mouseup', this.onMouseUp)
  },

  methods: {
    onToggle () {
      this.toggled = !this.toggled
      if (this.toggled) {
        this.width = 0
        this.calcMinWidth = 0
        this.maxWidth = 0
      } else {
        this.width = this.originWidth
        this.calcMinWidth =
          typeof this.minWidth === 'string'
            ? parseInt(this.minWidth)
            : this.minWidth
        this.maxWidth = this.originWidth
        setTimeout(() => {
          // 为了让展开和收起的速度一致，先把maxWidth放开到原宽度，过0.2s再设置为view的一半
          const parentNode = this.$refs.DraggableSider.parentNode
          this.maxWidth = Math.max(
            (parentNode.offsetWidth || document.documentElement.clientWidth) /
              2,
            parseInt(this.minWidth)
          )
        }, 200)
      }
      this.$emit('toggle')
    },

    onMouseDown (e) {
      this.dragging = true
      currentX = e.clientX
      currentWidth = parseInt(this.width)
    },

    onMouseMove (e) {
      if (!this.dragging) return
      const deltaX = e.clientX - currentX
      let finalWidth = 0
      if (this.side === 'left') {
        finalWidth = currentWidth + deltaX
      } else if (this.side === 'right') {
        finalWidth = currentWidth - deltaX
      }
      this.width = Math.min(
        Math.max(finalWidth, parseInt(this.minWidth)),
        this.maxWidth
      )
      this.$emit('mouseMove')
    },

    onMouseUp (e) {
      if (this.dragging) {
        this.dragging = false
        this.originWidth = this.width
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.draggable-sider {
  position: relative;
  height: 100%;
  // box-shadow: 2px 4px 6px 0 #e4e4e4;
  border-right: 1px solid #e4e4e4;
  transition: min-width 0.2s, max-width 0.2s;

  &__content {
    height: 100%;
    overflow-y: auto;
  }

  .border-handler {
    position: absolute;
    width: 6px;
    top: 0;
    bottom: 0;
    cursor: col-resize;
  }

  .tree-toggle {
    position: absolute;
    top: 50%;
    right: -20px;
    transform: translateY(-50px);
    opacity: 0;
    z-index: 999;
    transition: opacity 0.3s;
  }

  &:hover {
    .tree-toggle {
      opacity: 1;
    }
  }

  &.right {
    box-shadow: -2px 4px 6px 0 #e4e4e4;
    .tree-toggle {
      left: -20px;
      right: auto;
    }
  }

  &.toggled {
    .tree-toggle {
      // opacity: 1;
    }
  }
}
</style>
